#define _GNU_SOURCE

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <termios.h>
#include <unistd.h>
#include <sys/ioctl.h>

#include <assert.h>

/* --- Global Variables ---------------------------------------------------- */
int memcount = 0;

/* --- Additional functionallity ------------------------------------------- */
void *my_malloc (size_t s)
{
        void *s1 = malloc(s);
        assert(s1 != NULL);
        ++memcount;
        return s1;
}

void my_free(void *ptr){
        free(ptr);  
        --memcount;
}

/* --- Data Structures ---------------------------------------------------- */

struct address {
        char *name;
        char *address;
        char *phone; 
};

struct list_element {
        struct list_element *prev;
        struct list_element *next;
        struct address *addr; 
};

struct list {
        struct list_element *first;
        struct list_element *last; 
};

/* --- List Implementation ------------------------------------------------ */

struct list_element *list_new_elem (struct address *addr)
{
        struct list_element *elem = (struct list_element*) my_malloc (sizeof (struct list_element));
        elem->prev = elem;
        elem->next = elem;
        elem->addr = addr;

        return (elem);
}

struct list *list_new (void)
{
        struct list *list = (struct list*) my_malloc (sizeof (struct list));
        list->first = NULL;
        list->last  = NULL;
        
        return (list);
}

void list_append (struct list *list, struct address *addr)
{

        assert(list != NULL);
        assert(addr != NULL);
        
	struct list_element *elem = NULL;        
	elem = list_new_elem(addr);
        
	assert(elem != NULL);
        if (list->first == NULL && list->last == NULL)
        {
                list->first = elem;
                list->last  = elem;
                elem->prev  = elem;
                elem->next  = elem;
        }
        else
        {
                elem->prev = list->last;
                elem->next = list->first;
                struct list_element *tmp = list->last;
                tmp->next=elem;
                tmp = list->first;
                tmp->prev = elem;
                list->last = elem;
        }
}

void list_remove (struct list *list, struct list_element *elem)
{
        if (!elem || !list) { return; }

        if (elem == list->first && elem == list->last)
        {
                list->first = NULL;
                list->last  = NULL;
        }
        else if (elem == list->first)
        {
                list->first = elem->next;
                struct list_element *tmp = list->first;
                tmp->prev = list->last;
        }
        else if (elem == list->last)
        {
                list->last = elem->prev;
                struct list_element *tmp = list->last;
                tmp->next = list->first;
        }
        else
        {
                struct list_element *tmp = elem->prev;
                tmp->next = elem->next;
                tmp = elem->next;
                tmp->prev = elem->prev;
        }

        my_free (elem->addr);
        my_free (elem);
}

void list_release (struct list *list)
{
        assert(list != NULL);
        
        struct list_element *elem = list->first;
        while (elem != NULL)
        {
                list_remove (list, elem);
                elem = list->first;
        }

        my_free(list);
}
